The Impact of Human Activity on Whale Populations

The Impact of Human Activity on Whale Populations#

For decades, the vast and mysterious presence of whales has captivated both scientists and the public alike. These marine giants serve vital ecological functions, from regulating food webs to contributing to the global carbon cycle. Yet in the last century, the pressures exerted by industrial-scale fishing have brought their survival into question. As demand for seafood rises, concerns grow over the consequences this industry may have on the health of whale populations worldwide. (Block & Amudson, 2020)

While oversea transport and fishing is crucial for global trade, global food security, and coastal livelihoods, its side effects are increasingly hard to ignore. One particularly serious issue is whale bycatch, the accidental capture of whales in fishing gear. Combined with overlapping marine traffic and habitat disruption, these pressures raise urgent questions about how to balance marine resource use with conservation. Despite growing awareness, the scale and impact of these interactions remain difficult to quantify. (Moore et al., 2012)

To shed light on this issue, we analyzed data from multiple marine datasets covering whale bycatch, whale and ship activity, and fishing activity across several regions and years. Our goal was to understand the scale and geography of interactions between whales and human activity on sea. In doing so, we aimed to identify which whale species are most exposed, which regions pose the highest risk, if the problem has gotten somewhat better over the years, and how data-driven policy could help protect marine life while supporting sustainable fishing practices.

The Impact of Fishing Industries#

To understand the pressures facing whale populations today, it’s essential to first examine the broader trajectory of the fishing industry itself. The graph below illustrates the dramatic growth in global fishery production over the past six decades, a trend that reflects not only rising global demand for seafood but also the intensification of industrial fishing practices.

%run gdp.ipynb
<<<<<<< HEAD

From 1960 to the late 1980s, global capture fisheries production experienced a steady and steep rise, growing from around 300 million metric tons to over 700 million. This surge coincided with post-war technological advances in fishing vessels, sonar tracking, and cold storage, tools that allowed fleets to venture farther and stay out longer. The 1980s and 1990s marked a second, steeper climb, with production peaking around 2000, approaching nearly 1 billion metric tons annually (Pauly et al., 2005).

But the graph also tells a subtler story: since around 2000, global capture production has plateaued, with slight fluctuations but no sustained increase. This leveling off suggests that most of the world’s major fisheries have reached or exceeded their sustainable limits. Declines after 2015 in some years may even hint at early signs of nature consideration or stock collapses in certain regions.

For whales, this upward curve in fishing activity directly correlates with a rise in threats such as bycatch, gear entanglement, and habitat disruption. More fishing effort means more gear in the water, more ship traffic, and less available food in some shared ecosystems. Importantly, this global trend does not represent a uniform threat; certain regions and species are more exposed than others, as other graphs in this study show.

In short, this graph captures the historical momentum behind today’s marine pressures. While fisheries are essential for food security and livelihoods, their exponential growth over the past half-century has created widespread and systemic risks for marine megafauna like whales. Understanding these long-term trends helps frame the urgency for sustainable management, not just of fisheries, but of all life that shares the sea.

To understand the scope of this issue, we examined global fisheries production data. The map below shows total fisheries output by country, zoomed in to reflect the 95% range to avoid extreme outliers:

%run gdp2.ipynb
<<<<<<< HEAD

We observe that countries with vast coastlines or industrialized fleets, such as those in East Asia, North America, and parts of Africa, tend to dominate production. This aligns with what we know about the scale of fishing operations, and also with where whale populations often come into conflict with these activities.

From a data perspective, when plotted over time, total global fisheries production shows a sharp rise from the 1950s, peaking around 2000, and then stagnating. However, this plateau does not reflect reduced fishing pressure. Instead, it could imply that we’ve reached ecological limits in many regions. Despite stable yields, fishing effort, gear in the water, time at sea, intensity has not decreased.

One of the most devastating outcomes of industrial fishing is whale entanglement in gear such as gillnets, longlines, and trawls. These incidents, often fatal, are difficult to track and underreported, yet they are now among the leading causes of whale mortality.

This map, although not explicitly marking whale-human incidents, helps identify hotspots of risk: where large-scale fisheries intersect with known whale habitats. Regions with dark blue shading, especially parts of Asia and the Americas, are critical areas where both production and ecological risk converge.

Whale Endangerment#

To assess the dangers that whales have to deal with, we first have to see if this problem is actually as big as it is implied to be. To tell if it is, we used the IUCN Red List of threatened species, to give us an idea of how endangered every single species of whale actually is, this is visualized in the graph below:

%run piditje.ipynb
<<<<<<< HEAD
%run ship_strike_risk.ipynb
<<<<<<< HEAD
======= File ~/miniconda3/lib/python3.13/site-packages/pandas/io/parsers/readers.py:1620, in TextFileReader.__init__(self, f, engine, **kwds) 1617 self.options["has_index_names"] = kwds["has_index_names"] 1619 self.handles: IOHandles | None = None -> 1620 self._engine = self._make_engine(f, self.engine) File ~/miniconda3/lib/python3.13/site-packages/pandas/io/parsers/readers.py:1880, in TextFileReader._make_engine(self, f, engine) 1878 if "b" not in mode: 1879 mode += "b" -> 1880 self.handles = get_handle( 1881 f, 1882 mode, 1883 encoding=self.options.get("encoding", None), 1884 compression=self.options.get("compression", None), 1885 memory_map=self.options.get("memory_map", False), 1886 is_text=is_text, 1887 errors=self.options.get("encoding_errors", "strict"), 1888 storage_options=self.options.get("storage_options", None), 1889 ) 1890 assert self.handles is not None 1891 f = self.handles.handle File ~/miniconda3/lib/python3.13/site-packages/pandas/io/common.py:873, in get_handle(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options) 868 elif isinstance(handle, str): 869 # Check whether the filename is to be opened in binary mode. 870 # Binary mode does not support 'encoding' and 'newline'. 871 if ioargs.encoding and "b" not in ioargs.mode: 872 # Encoding --> 873 handle = open( 874 handle, 875 ioargs.mode, 876 encoding=ioargs.encoding, 877 errors=errors, 878 newline="", 879 ) 880 else: 881 # Binary mode 882 handle = open(handle, ioargs.mode) FileNotFoundError: [Errno 2] No such file or directory: 'aggregated_whale_data.csv'
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
Cell In[4], line 1
----> 1 get_ipython().run_line_magic('run', 'ship_strike_risk.ipynb')

File ~/miniconda3/lib/python3.13/site-packages/IPython/core/interactiveshell.py:2488, in InteractiveShell.run_line_magic(self, magic_name, line, _stack_depth)
   2486     kwargs['local_ns'] = self.get_local_scope(stack_depth)
   2487 with self.builtin_trap:
-> 2488     result = fn(*args, **kwargs)
   2490 # The code below prevents the output from being displayed
   2491 # when using magics with decorator @output_can_be_silenced
   2492 # when the last Python token in the expression is a ';'.
   2493 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):

File ~/miniconda3/lib/python3.13/site-packages/IPython/core/magics/execution.py:748, in ExecutionMagics.run(self, parameter_s, runner, file_finder)
    746     with preserve_keys(self.shell.user_ns, '__file__'):
    747         self.shell.user_ns['__file__'] = filename
--> 748         self.shell.safe_execfile_ipy(filename, raise_exceptions=True)
    749     return
    751 # Control the response to exit() calls made by the script being run

File ~/miniconda3/lib/python3.13/site-packages/IPython/core/interactiveshell.py:2979, in InteractiveShell.safe_execfile_ipy(self, fname, shell_futures, raise_exceptions)
   2977 result = self.run_cell(cell, silent=True, shell_futures=shell_futures)
   2978 if raise_exceptions:
-> 2979     result.raise_error()
   2980 elif not result.success:
   2981     break

File ~/miniconda3/lib/python3.13/site-packages/IPython/core/interactiveshell.py:310, in ExecutionResult.raise_error(self)
    308     raise self.error_before_exec
    309 if self.error_in_exec is not None:
--> 310     raise self.error_in_exec

    [... skipping hidden 1 frame]

File /tmp/ipykernel_70600/758615681.py:5
      2 import plotly.graph_objects as go
      4 # Load the data
----> 5 df = pd.read_csv('aggregated_whale_data.csv')
      7 blue_gradient = [
      8     [0.0, '#b3e0ff'], 
      9     [0.36, '#5b8cff'],
     10     [0.7, '#3a5ba0'],  
     11     [1.0, '#0a2463']  
     12 ]
     14 fig = go.Figure(go.Densitymap(
     15     lat=df['lat_bin'],
     16     lon=df['lon_bin'],
   (...)     30                   '<b>Risk Index:</b> %{z:.2f}<extra></extra>'
     31 ))

File ~/miniconda3/lib/python3.13/site-packages/pandas/io/parsers/readers.py:1026, in read_csv(filepath_or_buffer, sep, delimiter, header, names, index_col, usecols, dtype, engine, converters, true_values, false_values, skipinitialspace, skiprows, skipfooter, nrows, na_values, keep_default_na, na_filter, verbose, skip_blank_lines, parse_dates, infer_datetime_format, keep_date_col, date_parser, date_format, dayfirst, cache_dates, iterator, chunksize, compression, thousands, decimal, lineterminator, quotechar, quoting, doublequote, escapechar, comment, encoding, encoding_errors, dialect, on_bad_lines, delim_whitespace, low_memory, memory_map, float_precision, storage_options, dtype_backend)
   1013 kwds_defaults = _refine_defaults_read(
   1014     dialect,
   1015     delimiter,
   (...)   1022     dtype_backend=dtype_backend,
   1023 )
   1024 kwds.update(kwds_defaults)
-> 1026 return _read(filepath_or_buffer, kwds)

File ~/miniconda3/lib/python3.13/site-packages/pandas/io/parsers/readers.py:620, in _read(filepath_or_buffer, kwds)
    617 _validate_names(kwds.get("names", None))
    619 # Create the parser.
--> 620 parser = TextFileReader(filepath_or_buffer, **kwds)
    622 if chunksize or iterator:
    623     return parser

File ~/miniconda3/lib/python3.13/site-packages/pandas/io/parsers/readers.py:1620, in TextFileReader.__init__(self, f, engine, **kwds)
   1617     self.options["has_index_names"] = kwds["has_index_names"]
   1619 self.handles: IOHandles | None = None
-> 1620 self._engine = self._make_engine(f, self.engine)

File ~/miniconda3/lib/python3.13/site-packages/pandas/io/parsers/readers.py:1880, in TextFileReader._make_engine(self, f, engine)
   1878     if "b" not in mode:
   1879         mode += "b"
-> 1880 self.handles = get_handle(
   1881     f,
   1882     mode,
   1883     encoding=self.options.get("encoding", None),
   1884     compression=self.options.get("compression", None),
   1885     memory_map=self.options.get("memory_map", False),
   1886     is_text=is_text,
   1887     errors=self.options.get("encoding_errors", "strict"),
   1888     storage_options=self.options.get("storage_options", None),
   1889 )
   1890 assert self.handles is not None
   1891 f = self.handles.handle

File ~/miniconda3/lib/python3.13/site-packages/pandas/io/common.py:873, in get_handle(path_or_buf, mode, encoding, compression, memory_map, is_text, errors, storage_options)
    868 elif isinstance(handle, str):
    869     # Check whether the filename is to be opened in binary mode.
    870     # Binary mode does not support 'encoding' and 'newline'.
    871     if ioargs.encoding and "b" not in ioargs.mode:
    872         # Encoding
--> 873         handle = open(
    874             handle,
    875             ioargs.mode,
    876             encoding=ioargs.encoding,
    877             errors=errors,
    878             newline="",
    879         )
    880     else:
    881         # Binary mode
    882         handle = open(handle, ioargs.mode)

FileNotFoundError: [Errno 2] No such file or directory: 'aggregated_whale_data.csv'
>>>>>>> 3a88e9d2178b3d35b98b42b66527215951c00818